home *** CD-ROM | disk | FTP | other *** search
- ;;; JACAL: Symbolic Mathematics System. -*-scheme-*-
- ;;; Copyright 1992 Aubrey Jaffer.
- ;;; See the file "COPYING" for terms applying to this program.
-
- ;;; a LINE is a list of column positions and strings or characters
- ;;; which appear there on one horizontal line.
-
- ;;; a BOX is a list of pairs of line-numbers and LINEs.
- ;;; a PBOX consists of a BP (binding power) and a list of boxes.
-
- ;;; a TEMPLATE is an HBOX. An HBOX is a list of strings, symbols and
- ;;; VBOXes. A VBOX is a list of pairs of a row position and an HBOX
- ;;; or a list of a character.
-
- ;;; A number of the form #dNBBB in a template is replaced with the BOX
- ;;; for argument N. If the #dNBBB appears in a HBOX then it is glued
- ;;; horizontally to the other elements in the HBOX. If the #dNBBB
- ;;; appears in a VBOX then it is glued vertically to the other
- ;;; elements in the VBOX. BBB denotes the maximum binding power of
- ;;; the argument. If the binding power of the argument is less than
- ;;; BBB, parenthesis will be added according to TEMPLATE:PARENTHESIS.
-
- ;;; Characters in HBOXes are expanded horizontally to fill any empty
- ;;; space in their line. A list of a character VBOX is expanded
- ;;; vertically to fill any empty space in its containing HBOX.
-
- ;;; The symbol 'BREAK will break the line if there is not enough
- ;;; horizontal room remaining.
-
- (require 'rev3-procedures)
- (require 'common-list-functions)
-
- ;;; TEXT-WIDTH
-
- (define text-width string-length)
-
- ;;; return the position of symbol #dNBBB
-
- (define (arg-pos num)
- (quotient num 1000))
-
- (define (arg-bp num)
- (modulo num 1000))
-
- (define make-template cons)
- (define template-bp car)
- (define template-hbox cdr)
-
- ;;; Utility routines for dealing with BOX
- ;;; BOX is a list of (line-number-referred-to-center . LINE)
- ;;; LINE is a list of POSITIONs and STRINGs.
- ;(require 'record)
- ;(define pbox-type (make-record-type "box" '(bp lines)))
- ;(define make-pbox (record-constructor pbox-type))
- ;(define pbox-bp (record-accessor pbox-type 'bp))
- ;(define pbox-lines (record-accessor pbox-type 'lines))
-
- (define make-pbox cons)
- (define pbox-bp car)
- (define pbox-lines cdr)
-
- (define top-edge caar)
-
- (define left-edge cadar)
-
- (define (bottom-edge box)
- (caar (last-pair box)))
-
- (define (right-edge box)
- (define redge 0)
- (for-each
- (lambda (line)
- ;;; (define re 0)
- ;;; (for-each (lambda (x)
- ;;; (cond ((number? x) (set! re x))
- ;;; ((string? x)
- ;;; (set! re (+ (text-width x) re)))))
- ;;; (cdr line))
- ;;; (set! redge (max re redge))
- (if (not (null? (cdr line)))
- (let ((end (last line 2)))
- (set! redge (max redge (+ (car end)
- (if (string? (cadr end))
- (text-width (cadr end))
- 0)))))))
- box)
- redge)
-
- (define (shift-numbers! lst inc)
- (cond ((null? lst))
- (else (set-car! lst (+ inc (car lst)))
- (shift-numbers! (cddr lst) inc))))
-
- ;;; routines for actually writing the 2d formated output to a port.
- ;;; These can be replaced with code which does cursor positioning.
-
- (define (display-box linum box)
- (cond ((null? box) (+ 1 linum))
- ((>= linum (top-edge box))
- (display-line 0 #\ (cdar box))
- (if (> linum (top-edge box))
- (display "DISPLAY-BOX: out of sequence"))
- (newline)
- (display-box (+ 1 linum) (cdr box)))
- (else
- (newline)
- (display-box (+ 1 linum) box))))
-
- (define (display-line hpos fillchr line)
- (cond ((null? line) hpos)
- ((string? (cadr line))
- (display (make-string (- (car line) hpos) fillchr))
- (display (cadr line))
- (display-line (+ (car line) (text-width (cadr line)))
- fillchr
- (cddr line)))
- ((char? (cadr line))
- (display (make-string (- (car line) hpos) fillchr))
- (display-line (car line)
- (cadr line)
- (cddr line)))
- (else (error "DISPLAY-LINE: problem in?" line))))
-
- ;;; Glue 2 boxes together horizontally, with the RIGHTBOX moved
- ;;; POSINC to the right
-
- (define (hglue-lines! leftbox posinc rightbox)
- (cond ((null? rightbox) leftbox)
- ((null? leftbox) '())
- ((char? (car rightbox))
- (cons (nconc (car leftbox) (list posinc (string (car rightbox))))
- (hglue-lines! (cdr leftbox) posinc rightbox)))
- ((< (top-edge leftbox) (top-edge rightbox))
- (cons (car leftbox)
- (hglue-lines! (cdr leftbox) posinc rightbox)))
- (else ;line up
- (if (not (zero? posinc)) (shift-numbers! (cdar rightbox) posinc))
- (cons (nconc (car leftbox) (cdar rightbox))
- (hglue-lines! (cdr leftbox) posinc (cdr rightbox))))))
-
- (define (hglue boxes hroom)
- (let ((arights (list (cond ((null? (car boxes)) 0)
- ((char? (car (car boxes))) 1)
- (else (right-edge (car boxes))))))
- (right -1) (top 0) (bottom 0))
- (do ((boxes boxes (cdr boxes))
- (rights
- arights
- (begin (set-cdr!
- rights
- (if (null? (cdr boxes)) '()
- (list (cond ((null? (cadr boxes)) 0)
- ((char? (caadr boxes)) 1)
- (else (right-edge (cadr boxes)))))))
- (cdr rights)))
- (redge 0 (+ redge (car rights))))
- ((or (null? boxes) (and (positive? right) (> redge hroom)))
- (if (<= redge hroom) (set! right -2)))
- (cond ((equal? (car boxes) '((0 0 break)))
- (set! right redge))
- ((char? (caar boxes)))
- (else (set! bottom (max bottom (bottom-edge (car boxes))))
- (set! top (min top (top-edge (car boxes)))))))
- (do ((boxes boxes (cdr boxes))
- (rights arights (cdr rights))
- (redge 0 (+ redge (car rights)))
- (leftbox
- (do ((i (+ -1 bottom) (+ -1 i))
- (ans (list (list bottom)) (cons (list i) ans)))
- ((< i top) ans))
- (cond
- ((equal? (car boxes) '((0 0 break)))
- (cond ((= (+ redge (car rights)) right)
- (set! arights #f)
- (vformat! '((0 #d0000) (2 #d1000))
- (list (make-pbox 200 (list leftbox))
- (make-pbox 200 (cdr boxes)))
- #f hroom))
- (else leftbox)))
- (else (hglue-lines! leftbox redge (car boxes))))))
- ((or (not arights) (null? boxes)) leftbox))))
-
- ;;; Routines to format BOX from TEMPLATEs.
-
- ;;; HFORMAT returns a list of boxes which need to be HGLUEd together
- ;;; into a single box.
-
- (define (hformat hbox args tps hroom)
- (if (null? hbox) '()
- (let ((item (car hbox)) (hr (- hroom (quotient hroom 20))))
- (cond
- ((number? item)
- (let ((argnum (arg-pos item)))
- (if (> (length args) argnum)
- (let ((arg (list-ref args argnum)))
- (if (<= (arg-bp item) (pbox-bp arg))
- (nconc (pbox-lines arg)
- (hformat (cdr hbox) args tps hroom))
- (nconc
- (hformat
- (template-hbox (cdr (assq 'template:parenthesis tps)))
- (list '() arg) tps hroom)
- (hformat (cdr hbox) args tps hroom))))
- (hformat (cdr hbox) args tps hroom))))
- ((pair? item)
- (cons (vformat! item args tps hr)
- (hformat (cdr hbox) args tps hroom)))
- ((vector? item)
- (let ((vt (vector-ref item 0))
- (vl (cdr (vector->list item))))
- (cond ((<= (length args) (arg-pos (find-if number? vl)))
- (hformat (cdr hbox) args tps hroom))
- ((eq? 'REST vt)
- (nconc (hformat vl args tps hroom)
- (hformat hbox (cdr args) tps (- hroom hr))))
- ((eq? 'OPTIONAL vt)
- (nconc (hformat vl args tps hroom)
- (hformat (cdr hbox) args tps hroom)))
- (else (error "HFORMAT: unknown format" item)))))
- (else (cons (list (list 0 0 item))
- (hformat (cdr hbox) args tps hroom)))))))
-
- (define (vformat! vbox args tps hroom)
- (if (char? (car vbox))
- vbox
- (let* ((boxes (map (lambda (hbox)
- (hglue (hformat (cdr hbox) args tps hroom)
- hroom))
- vbox))
- (rights (map right-edge boxes))
- (mostright (apply max rights)))
- (for-each
- (lambda (box right)
- (for-each
- (lambda (line)
- (cond ((null? (cdr line)))
- ((and (char? (caddr line)) (null? (cdddr line)))
- ;;terminate rubber line.
- (nconc line (list mostright #\ )))
- (else ;center justify line.
- (let ((lst (cdr line))
- (inc (quotient (- mostright right) 2)))
- (set-car! lst (+ inc (car lst)))
- (shift-numbers! (cddr lst) inc)))))
- box))
- boxes
- rights)
- (vrenumber! vbox boxes)
- (apply nconc boxes))))
-
- ;;; the trick here is to make line 0 of hbox 0 still be line 0. Push
- ;;; everything else up or down to make that happen.
- ;;; Here, vbox is used only for its hbox numbers.
- (define (vrenumber! vbox boxes)
- (cond ((null? vbox) 0)
- ((negative? (caar vbox))
- (let ((topinc (+ (- (caar vbox)
- (if (null? (cdr vbox)) 0 (caadr vbox)))
- (- (vrenumber! (cdr vbox) (cdr boxes))
- (bottom-edge (car boxes))))))
- (or (zero? topinc)
- (for-each
- (lambda (line)
- (set-car! line (+ (car line) topinc)))
- (car boxes))))
- (top-edge (car boxes)))
- (else
- (or (zero? (caar vbox))
- (for-each ;space down if no hbox 0
- (lambda (line)
- (set-car! line (+ (car line) (caar vbox))))
- (car boxes)))
- (let ((topinc (bottom-edge (car boxes)))
- (lastnum (caar vbox)))
- (for-each
- (lambda (hbox box)
- (set! topinc (+ (- (car hbox) lastnum)
- (- topinc (top-edge box))))
- (set! lastnum (car hbox))
- (for-each
- (lambda (line)
- (set-car! line (+ (car line) topinc)))
- box)
- (set! topinc (bottom-edge box)))
- (cdr vbox)
- (cdr boxes)))
- (top-edge (car boxes)))))
-
- ;;; Driver for 2d output
-
- (define (inprint exp grm)
- (tprint exp (grammar-write-tab grm)))
-
- (define (tprint exp tps)
- (let* ((owidth (output-port-width (current-output-port)))
- (box (hglue (pbox-lines (unparse exp tps owidth)) owidth)))
- (display-box (top-edge box) box)))
-
- (define (unparse exp tps hroom)
- (cond ((symbol? exp)
- (make-pbox 200 (list (list (list 0 0 (symbol->string exp))))))
- ((number? exp)
- (make-pbox 200 (list (list (list 0 0 (number->string exp))))))
- ((list? exp)
- (let* ((p (assq (car exp) tps)))
- (unparse1 (if p (cdr p) (cdr (assq 'TEMPLATE:DEFAULT tps)))
- exp tps hroom)))
- ((not (vector? exp))
- (slib:error "UNPARSE: not s-expression" exp))
- ((zero? (vector-length exp)) ;this special case should be eliminated
- (make-pbox 200 (list (list (list 0 0 "[]")))))
- ((and (vector? (vector-ref exp 0))
- (assq 'TEMPLATE:MATRIX tps)
- (let ((len (vector-length (vector-ref exp 0))))
- (every (lambda (r) (and (vector? r) (= (vector-length r) len)))
- (cdr (vector->list exp)))))
- (let ((hr (quotient hroom (vector-length exp)))
- (template (cdr (assq 'TEMPLATE:MATRIX tps))))
- (make-pbox
- (template-bp template)
- (hformat
- (template-hbox template)
- (map (lambda (obj)
- (unparse1 (rubber-vbox (length obj)) obj tps hr))
- ;transpose of exp
- (apply map list (map vector->list
- (vector->list exp))))
- tps hroom))))
- (else (unparse1 (cdr (assq 'TEMPLATE:BUNCH tps))
- (vector->list exp) tps hroom))))
-
- (define (unparse1 template exp tps hroom)
- (define hr (- hroom (quotient hroom 20)))
- (make-pbox (template-bp template)
- (hformat (template-hbox template)
- (map (lambda (exp)
- (unparse exp tps hr))
- exp)
- tps hroom)))
-
- (define (rubber-vbox len)
- (make-template 200 (list (rubvbox (- 1 len) len))))
-
- (define (rubvbox i len)
- (if (>= i len) '()
- (cons (list i (+ (* 1000 (quotient (+ i len) 2)) 10))
- (rubvbox (+ i 2) len))))
-
- ;;;; Test code
- ;;; To test, load this and stdgrm.scm. Do (test2d tps:2d).
-
- (define (test2d tps)
- (for-each
- (lambda (b) (tprint b tps) (newline))
- '(
- (+ (* 3 a b) (* 2 (^ a 2) b) c (* d e))
- (sum (* (rapply a i) (^ x (- i 2))) i 0 inf)
- (= %gamma (limit (sum (- (over 1 n) (log m)) n 1 m) m inf))
- (^ (- (over 1 (^ (+ y x) 4)) (over 3 (^ (+ y x) 3))) 2)
- (^ x (over (+ (^ a 2) 1) a))
- (+ (- (over 2 (+ x 2)) (over 2 (+ x 1)))
- (over 1 (^ (+ x 1) 2)))
- (over (* (+ (^ x 2) (* 2 x) 1) (- y 1))
- (* 36 (+ y 1)))
- (+ (* (^ %e (f x)) ((over (^ d 2) (^ dx 2)) (f x)))
- (* (^ %e (f x)) (^ ((over d dx) (f x)) 2)))
- (+ (integrate (f x) x a b) x)
- (limit (^ (f x) (g (+ x 1))) x 0 minus)
- (+ (over y (^ (box x) 2)) x)
- (over (prod (^ (+ (^ x i) 1) (/ 5 2)) i 1 inf)
- (+ (^ x 2) 1))
- (over 1 (+ 4 (over 1 (+ 3 (over 1 42)))))
- (over (* (factorial m) n (factorial (- n 1))) m)
- (- (* 16 (^ a 2))
- (* 2 (u 0 1) (at ((over d dx) (u x y)) (= x 0) (= y 1))))
- )))
-
- (define (textest)
- (for-each
- (lambda (b)
- (tprint b tps:2d) (newline)
- (tprint b tps:tex) (newline))
- '(
- (over (+ (^ a 2) c (* b x)) (+ 2 z))
- (+ (^ (+ a b) (/ 1 2)) (^ e (/ 1 2)))
- (arctan (arctan a))
- (over (arctan
- (over (- (/ (* 2 (^ b (/ 1 4)) x) (^ a (/ 1 4)))
- (sqrt 2))
- (sqrt 2)))
- (* (^ 2 (/ 3 2)) (^ a (/ 3 4)) (^ b (/ 1 4))))
- (over a (+ b c)))))
-
- (define (mtest tps)
- (for-each
- (lambda (b) (tprint b tps) (newline))
- '(
- #((= x1 (negate (over 1 (sqrt 5))))
- (= x2 (negate (over 2 (sqrt 5)))))
- #(#((over 1 a) 0) #((negate (over b a)) 1))
- #(#((^ a 2) 0) #((+ (* a b) b) 1)))))
-